/*
 * vue-cropper 文档
 * Github: https://github.com/xyxiao001/vue-cropper
 * NPM: https://www.npmjs.com/package/vue-cropper
 * ———————————————————————————————————————————————————
 * 我想对您说的话:
 * 1. 您可根据自己的UI框架进行改造,本示例虽是Element,但原理都一样
 * 2. 大部分框架的上传组件都默认自动上传,您必须禁止并改为手动上传,因为需要裁剪图片
 * 3. 这款图片裁剪插件最后裁剪完成后,得到了是一个Blob对象或base64编码,不懂可以百度
 * 4. 您需要与后端进行沟通,让接口接收Blob对象或base64编码,如果后端告诉你不会接收则找他毛病就行了
 * 5. 您调用接口时,不能将Blob直接传给后端,而是必须要使用formData进行包裹,不懂可以百度
 * 6. 当然,Blob/File/base64数据格式之间支持互相转换,如有需要不懂可以百度
 * 7. 调用接口时,记得将headers添加一对'Content-Type': 'multipart/form-data',否则会有问题
 * 8. 如果您考虑到分割组件,请将整个例子当成组件,放在模态框中引入即可,当然您也可以自行分割
 * 9. 页面任何地方都能自定义,您根据需求更改即可
 * 10. 页面样式没有美化,考虑到诸多css可能会影响您分析代码,所以请您自己根据需求来美化
 */

<template>
  <div>

    <!-- 原始上传图片 -->
    <!-- 禁用显示已上传文件列表|禁用自动上传 -->
    <template v-if="!isPreview">
      <el-upload
      :action="action"
      :drag="true"
      :auto-upload="false"
      :show-file-list="false"
      :on-change="uploadChange"
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">点击上传</div>
        <div class="el-upload__tip">
          支持绝大多数图片格式，单张图片最大支持5MB
        </div>
      </el-upload>
    </template>
    <!-- END -->

    <!-- 裁剪完成显示预览 -->
    <!-- 请根据自身需求进行改造或删除 -->
    <div v-else>
      <div class="perview-content">
          <el-upload
          action="action"
          :auto-upload="false"
          :show-file-list="false"
          :on-change="uploadChange">
          <img :src="previewImg" alt="裁剪图片" />
          </el-upload>
      </div>
    </div>
    <!-- END -->

    <!-- 剪裁图片弹框 -->
    <el-dialog
    title="图片剪裁器"
    :visible.sync="dialogVisible"
    :center="true"
    :close-on-click-modal="false"
    :append-to-body="true"
    width="700px">
        <div class="cropper-content">
          <vueCropper
          ref="cropper"
          :img="option.img"
          :outputSize="option.size"
          :outputType="option.outputType"
          :info="true"
          :full="option.full"
          :canMove="option.canMove"
          :canMoveBox="option.canMoveBox"
          :original="option.original"
          :autoCrop="option.autoCrop"
          :fixed="option.fixed"
          :fixedNumber="option.fixedNumber"
          :centerBox="option.centerBox"
          :infoTrue="option.infoTrue"
          :fixedBox="option.fixedBox"
          :autoCropWidth="option.autoCropWidth"
          :autoCropHeight="option.autoCropHeight"
          @cropMoving="cropMoving"
          />
        </div>

      <div class="button-group">
        <!-- 工具组 -->
        <el-button-group>
          <el-button @click="changeScaleHandle(1)" type="primary" icon="el-icon-zoom-in">放大</el-button>
          <el-button @click="changeScaleHandle(-1)" type="primary">缩小<i class="el-icon-zoom-out el-icon--right"></i></el-button>
          <el-button @click="rotateLeftHandle" type="primary" icon="el-icon-arrow-left">左旋转</el-button>
          <el-button @click="rotateRightHandle" type="primary">右旋转<i class="el-icon-arrow-right el-icon--right"></i></el-button>
          <el-button @click="downloadHandle('blob')" type="primary" icon="el-icon-download" >下载到本地</el-button>
        </el-button-group>
      </div>
      
      <div slot="footer">
        <!-- 插槽底部 -->
        <el-upload
        :action="action"
        :auto-upload="false"
        :show-file-list="false"
        :on-change="uploadChange"
        class="upload-reset"
        >
          <el-button icon="el-icon-refresh">换个图</el-button>
        </el-upload>
        <el-button
        type="primary"
        @click="finish"
        :loading="loading"
        icon="el-icon-circle-check"
        style="width: 130px"
        >保存提交</el-button>
      </div>
    </el-dialog>
    <!-- END -->

    <div>
      <h3>1. 由于这是elementUI公共接口,随时可能失效,如失效请更换</h3>
      <h3>2. 如出示例接口出现跨域或报错情况,请尝试刷新页面裁剪提交几次,或者裁剪区域小一些，这个公共接口不接收太大的图片，也可能资源紧张</h3>
      <h3>3. 如接口遇到任何问题,请找后端调试,前端保证没问题</h3>
    </div>

  </div>
</template>

<script>

// 裁剪组件与请求库
import { VueCropper } from 'vue-cropper'
import axios from 'axios'

export default {
  components: { VueCropper }, 
  data() {
    return {

      /* 1. 由于这是elementUI公共接口,随时可能失效,如失效请更换 */
      /* 2. 如出示例接口出现跨域或报错情况,请尝试刷新页面裁剪提交几次,或者裁剪区域小一些，这个公共接口不接收太大的图片，也可能资源紧张 */
      /* 3. 如接口遇到任何问题,请找后端调试,前端保证没问题 */
      action: "https://jsonplaceholder.typicode.com/posts/",
    
      previewImg: "",//图片地址(仅预览使用)
      isPreview: false,//裁剪完成关闭模态框预览(标识)
      dialogVisible: false,//是否显示裁剪框(模态框)

      // 防止重复提交标识(裁剪成功标为true,反之重置为false)
      loading: false,//是否可以继续提交

      // 裁剪组件配置(详见链接)
      // Github: https://github.com/xyxiao001/vue-cropper
      // npm: https://www.npmjs.com/package/vue-cropper
      option: {
        img: "", //裁剪图片的地址
        info: true, //裁剪框的大小信息
        outputSize: 1, //裁剪生成图片的质量
        outputType: "png", //裁剪生成图片的格式
        canScale: true, //图片是否允许滚轮缩放
        autoCrop: true, //是否默认生成截图框
        canMoveBox: true, //截图框能否拖动
        autoCropWidth: 200, //默认生成截图框宽度
        autoCropHeight: 200, //默认生成截图框高度
        fixedBox: false, //固定截图框大小(不允许改变)
        fixed: true, //是否开启截图框宽高固定比例
        fixedNumber: [6, 4], //截图框的宽高比例
        full: false, //是否输出原图比例的截图
        original: false, //上传图片按照原始比例渲染
        centerBox: false, //截图框是否被限制在图片里面
        infoTrue: true, //true为展示真实输出图片宽高(false展示看到的截图框宽高)
      },
    }
  },

  methods: {

    /**
     * 上传文件状态改变(用于限制或校验文件)
     * @description 添加文件/上传成功和上传失败时都会被调用
     * @param {Object} file - file
     * @param {Array} fileList - fileList
     * @return Boolean
     */
    uploadChange(file, fileList) {
      // console.log(file, fileList)
      // 校验文件
      const isJPG = file.raw.type === "image/jpeg" || file.raw.type === "image/png"
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isJPG) {
        this.$message.error("上传头像图片只能是 JPG/PNG 格式!")
        return false
      }
      if (!isLt2M) {
        this.$message.error("上传头像图片大小不能超过 2MB!")
        return false
      }
      
      // 文件合法正常通过(赋值给裁剪框显示图片)
      this.$nextTick(async () => {
        // base64方式(this.option.img = await fileByBase64(file.raw))
        // DOMString方式
        this.option.img = URL.createObjectURL(file.raw)

        // 重置防止重复提交标识与打开裁剪模态框
        this.loading = false
        this.dialogVisible = true
      })
    },


    /**
     * 下载图片到本地
     * @description 不上传到服务器直接下载
     * @param {*} type
     * @return void
     */
    downloadHandle(type) {
      // 创建DOM
      let aLink = document.createElement("a")
      aLink.download = "image"//文件名

      // Blob方式
      if (type === "blob") {
        this.$refs.cropper.getCropBlob((data) => {
          // console.log(URL.createObjectURL(data))
          aLink.href = URL.createObjectURL(data)
          aLink.click()
        })
      }
      
      // Base64方式(如不需要可删除)
      else {
        this.$refs.cropper.getCropData((data) => {
          aLink.href = data
          aLink.click()
        })
      }
    },


    /**
     * 获取裁剪后的图片
     * @description 可获取Blob/base64格式(传给接口)
     * @return void
     */
    finish() {
      // 获取截图的 blob 数据
      this.$refs.cropper.getCropBlob((blob) => {
        // 业务逻辑
        this.http(blob)
      })

      // [获取截图的 base64 数据]
      // this.$refs.cropper.getCropData(data => {
      //     // 业务逻辑
      //     console.log(data)
      // })
    },

    
    /**
     * 上传到服务器
     * @description 调用接口
     * @param {Object} blob - [最终数据]裁剪图片blob数据对象
     * @return void
     */
    http(blob) {
      // 封装formData对象
      const formData = new FormData()
      formData.append('file', blob)

      // 整理请求参数(注意headers必须设置)
      const param = {
        url: this.action, method: 'post',
        headers: {'Content-Type': 'multipart/form-data'}, data: formData
      }

      // 发起请求
      axios(param).then((res) => {
        if(res.status == '201') {//接口成功
          // 设置图片预览地址与开启预览
          this.previewImg = URL.createObjectURL(blob)
          this.isPreview = true

          // 禁用上传与关闭模态框
          this.loading = true
          this.dialogVisible = false
        }else{
          this.$message.error('图片上传失败')
        }
      })
    },


    /**
     * 截图框移动
     * @description 回调函数
     * @param {Object} data - 参数
     * @return void
     */
    cropMoving(data) {
      // 截图框的左上角 x，y和右下角坐标x，y
      // let cropAxis = [data.axis.x1, data.axis.y1, data.axis.x2, data.axis.y2]
      // console.log(cropAxis)
    },


    // 放大/缩小
    changeScaleHandle(num) { num = num || 1; this.$refs.cropper.changeScale(num)},
    // 左旋转
    rotateLeftHandle() { this.$refs.cropper.rotateLeft()},
    // 右旋转
    rotateRightHandle() { this.$refs.cropper.rotateRight()},
    // 清理图片
    clearImgHandle() { this.option.img = ""},

  }
}
</script>

<style scoped>
/* 只写了简单的样式，请根据您的需求进行美化 */
.upload-reset{
  display: inline-block;
  margin-right: 15px;
}
.cropper-content{
  width: auto;
  height: 350px;
}
.button-group{
  text-align: center;
  margin-top: 30px;
}
.perview-content{
  width: 400px;
  /* background: red; */
  padding: 20px;
  border:5px dashed rgb(150, 150, 150)
}
</style>